﻿using CommonBehaviors.Actions;
using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.Pathing;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Media;
using Action = Styx.TreeSharp.Action;

using F = Hunter.GUI.Form1;
using HKM = Hunter.Helpers.HotkeyManager;
using EH = Hunter.Handlers.EventHandlers;
using CL = Hunter.Handlers.CombatLogEventArgs;
using SP = Hunter.CRSettings.CRSettings;
using R = Hunter.Rotation.rotations;
using CS = Hunter.Spells.SpellCasting;
using EI = Hunter.Helpers.UseItems;
using T = Hunter.Helpers.targets;
using M = Hunter.Helpers.Movement;
using UN = Hunter.Helpers.Unit;
using BM = Hunter.Rotation.BMRotation;

namespace Hunter
{
    public class Main : CombatRoutine
    {
        public override string Name { get { return "Hunter Routine by Pasterke"; } }
        public override WoWClass Class { get { return WoWClass.Hunter; } }

        public LocalPlayer Me { get { return StyxWoW.Me; } }

        public override Composite CombatBehavior { get { return Combat(); } }
        public override Composite PreCombatBuffBehavior { get { return PreCombatBuffs(); } }
        public override Composite CombatBuffBehavior { get { return CombatBuffs(); } }
        public override Composite PullBehavior { get { return Pull(); } }
        //public override Composite PullBuffBehavior { get { return PullBuffs(); } }

        public string usedBot { get { return BotManager.Current.Name.ToUpper(); } }

        private static bool init { get; set; }
        private static bool IsInGame
        {
            get { return StyxWoW.IsInGame; }
        }
        public Stopwatch mountTimer = new Stopwatch();
        public override bool WantButton { get { return true; } }
        public override void OnButtonPress()
        {
            F ConfigForm = new F();
            ConfigForm.ShowDialog();
        }
        public static DateTime nextCallAllowed;
        public static void SetNextCallAllowed()
        {
            nextCallAllowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 4000);
        }

        public override void Initialize()
        {
            Logging.Write("\r\n" + "--------------------------------");
            Logging.Write("-- Hello {0}                  --", Me.Name);
            Logging.Write("--      Thanks for using      --");
            Logging.Write("-- The Hunter Combat Routine  --");
            Logging.Write("--       by Pasterke          --");
            Logging.Write("--------------------------------" + "\r\n");
            HKM.registerHotKeys();
            Lua.Events.AttachEvent("UI_ERROR_MESSAGE", CL.CombatLogErrorHandler);
            EH.AttachCombatLogEvent();
            SetNextCallAllowed();
            MessageBox.Show("BeastMaster + Survival supported", "Hunter Routine by Pasterke");
            
        }
        public override void ShutDown()
        {
            HKM.removeHotkeys();
            EH.DetachCombatLogEvent();
            Lua.Events.DetachEvent("UI_ERROR_MESSAGE", CL.CombatLogErrorHandler);
        }

        #region Pulse
        public override void Pulse()
        {
            if (!StyxWoW.IsInWorld || Me == null || !Me.IsValid || Me.IsGhost)
            {
                return;
            }
            if (Me.IsDead
                && AutoBot)
            {
                Lua.DoString(string.Format("RunMacroText(\"{0}\")", "/script RepopMe()"));
            }
        }
        #endregion
        public override bool NeedRest
        {
            get
            {
                return CanBuff
                    && !UN.buffExists(CS.FEIGN_DEATH, Me)
                    && !HKM.pauseRoutineOn
                    && !HKM.manualOn
                    && !Me.GroupInfo.IsInParty
                    && Me.HealthPercent <= SP.myPrefs.FoodHPOoC;
            }
        }

        public override void Rest()
        {
            if (CanBuff
                && !Me.IsSwimming
                && Me.HealthPercent <= SP.myPrefs.FoodHPOoC)
            {
                Styx.CommonBot.Rest.Feed();
            }

        }

        Composite Pull()
        {
            return new PrioritySelector(
                new Decorator(ret => HKM.pauseRoutineOn || HKM.manualOn || UN.buffExists(CS.FEIGN_DEATH, Me), Hold()),
                new Decorator(ret => Me.CurrentTarget == null || Me.CurrentTarget.IsDead
                    && SP.myPrefs.AutoPetTarget
                    && Me.GotAlivePet
                    && Me.Pet.GotTarget
                    && !Me.Pet.CurrentTarget.Name.Contains("Nazgrim")
                    && Me.PetInCombat,
                    new Action(ret => { Me.Pet.Target(); return RunStatus.Failure; })),
                new Decorator(ret => (Me.CurrentTarget == null || (Me.GotTarget && Me.CurrentTarget.IsDead)) && M.AllowTargeting, T.FindTarget()),
                new Decorator(ret => Me.GotTarget
                    && M.AllowTargeting
                    && Me.CurrentTarget.Distance > 39
                    && T.MeleeAddCount >= 1, T.FindMeleeAttackers()),
                new Decorator(ret => Me.CurrentTarget != null
                    && AutoBot
                    && Me.CurrentTarget.IsFriendly, new Action(ret => { Me.ClearTarget(); return RunStatus.Failure; })),
                new Decorator(ret => SP.myPrefs.FlaskAlchemy
                    && EI.HasItem(AlchemyFlask)
                    && !Me.HasAura(CS.FLASK_OF_SPRING_BLOSSOMS_BUFF)
                    && !Me.HasAura(CS.CRYSTAL_OF_INSANITY_BUFF)
                    && !Me.HasAura("Enhanced Agility"), EI.UseItem(AlchemyFlask)),
                new Decorator(ret => Me.GotTarget && M.AllowMovement && Me.CurrentTarget.Distance > 39, M.CreateMovement()),
                new Decorator(ret => Me.GotTarget && M.AllowMovement && Me.CurrentTarget.Distance <= 39, M.CreateStopMovement()),
                new Decorator(ret => Me.GotTarget && M.AllowFacing && !Me.IsSafelyFacing(Me.CurrentTarget), M.FacingTarget()),
                new Decorator(ret => Me.GotTarget && Me.CurrentTarget.Distance <= 39 && !UN.buffExists(CS.MISDIRECTION, Me) && CS.LastSpell != CS.MISDIRECTION, CS.castMisdirection()),
                CS.CastArcaneShot()
                );
        }
        Composite PreCombatBuffs()
        {
            return new PrioritySelector(
                new Decorator(ret => UN.buffExists(CS.FEIGN_DEATH, Me) || HKM.pauseRoutineOn, Hold()),
                new Decorator(ret => SP.myPrefs.AgilityFlask == 4
                    && !Me.HasAura(CS.FLASK_OF_SPRING_BLOSSOMS_BUFF)
                    && (Me.CurrentMap.IsInstance || Me.CurrentMap.IsDungeon)
                    && EI.HasItem(AgilityFlask), EI.UseItem(AgilityFlask)),
                new Decorator(ret => SP.myPrefs.AgilityFlask == 2
                    && !Me.HasAura(CS.FLASK_OF_SPRING_BLOSSOMS_BUFF)
                    && (Me.CurrentMap.IsRaid || Me.GroupInfo.IsInRaid)
                    && EI.HasItem(AgilityFlask), EI.UseItem(AgilityFlask)),
                new Decorator(ret => SP.myPrefs.AgilityFlask == 3
                    && !Me.HasAura(CS.FLASK_OF_SPRING_BLOSSOMS_BUFF)
                    && Me.CurrentMap.IsRaid
                    && !Me.GroupInfo.IsInLfgParty
                    && EI.HasItem(AgilityFlask), EI.UseItem(AgilityFlask)),
                new Decorator(ret => SP.myPrefs.FlaskCrystal
                    && EI.HasItem(crystal)
                    && !Me.HasAura(CS.FLASK_OF_SPRING_BLOSSOMS_BUFF)
                    && !Me.HasAura(CS.CRYSTAL_OF_INSANITY_BUFF), EI.UseItem(crystal)),
                new Decorator(ret => SP.myPrefs.FlaskAlchemy
                    && !Me.HasAura(CS.CRYSTAL_OF_INSANITY_BUFF)
                    && !Me.HasAura(CS.FLASK_OF_SPRING_BLOSSOMS_BUFF)
                    && !Me.HasAura("Enhanced Agility")
                    && EI.HasItem(AlchemyFlask), EI.UseItem(AlchemyFlask)),
                CS.CallPet(),
                CS.RevivePet(),
                CS.ReviveDeadPet(),
                CS.CastTrapLauncher()
                );
        }
        Composite CombatBuffs()
        {
            return new PrioritySelector(
                new Decorator(ret => UN.buffExists(CS.FEIGN_DEATH, Me) || HKM.pauseRoutineOn, Hold()),
                
                CS.CallPet(),
                CS.RevivePet(),
                CS.ReviveDeadPet(),
                new Decorator(ret => CanBuff && Me.HealthPercent <= SP.myPrefs.PercentDeterrence, CS.CastDeterrence()),
                new Decorator(ret => CanBuff && Me.HealthPercent <= SP.myPrefs.PercentHealthstone && EI.HasItem((uint)healthstone), EI.UseItem((uint)healthstone)),
                new Decorator(ret => CanBuff && Me.HealthPercent <= SP.myPrefs.PercentExhilaration, CS.CastExhilaration()),
                new Decorator(ret => CanBuff && !UN.buffExists(CS.TRAP_LAUNCHER, Me) && CS.LastSpell != CS.TRAP_LAUNCHER, CS.CastTrapLauncher()),
                new Decorator(ret => CanBuff && Me.HealthPercent <= SP.myPrefs.PercentNaaru, CS.CastNaruu())
                );
        }
        Composite Combat()
        {
            return new PrioritySelector(
                new Decorator(ret => (Me.Mounted && !AutoBot) || HKM.pauseRoutineOn || HKM.manualOn || UN.buffExists(CS.FEIGN_DEATH, Me), Hold()),
                new Decorator(ret => SP.myPrefs.AutoPetTarget
                    && (Me.CurrentTarget == null || Me.CurrentTarget.IsDead)
                    && Me.Pet != null
                    && Me.GotAlivePet
                    && (Me.PetAggro || Me.PetInCombat),
                    new Action(ret =>
                    {
                        if (Me.Pet != null && Me.Pet.GotTarget)
                        {
                            Me.Pet.CurrentTarget.Target();
                            Logging.Write(Colors.Pink, "Taking my Pet's Target " + Me.Pet.CurrentTarget.Name);
                            return RunStatus.Success;
                        }
                        return RunStatus.Failure;
                    })),
                new Decorator(ret => (Me.CurrentTarget == null || (Me.GotTarget && Me.CurrentTarget.IsDead)) && M.AllowTargeting, T.FindTarget()),
                new Decorator(ret => Me.GotTarget
                    && M.AllowTargeting
                    && !Me.CurrentTarget.IsWithinMeleeRange
                    && T.MeleeAddCount >= 1, T.FindMeleeAttackers()),
                new Decorator(ret => Me.CurrentTarget != null
                    && AutoBot
                    && Me.CurrentTarget.IsFriendly, new Action(ret => { Me.ClearTarget(); return RunStatus.Failure; })),
                new Decorator(ret => Me.GotTarget && M.AllowMovement && Me.CurrentTarget.Distance > 39, M.CreateMovement()),
                new Decorator(ret => Me.GotTarget && M.AllowMovement && Me.CurrentTarget.Distance <= 39, M.CreateStopMovement()),
                new Decorator(ret => Me.GotTarget && M.AllowFacing && !Me.IsSafelyFacing(Me.CurrentTarget), M.FacingTarget()),
                new Decorator(ret => Me.GotTarget && Me.Specialization == WoWSpec.HunterSurvival, R.Rotation()),
                new Decorator(ret => Me.GotTarget && Me.Specialization == WoWSpec.HunterBeastMastery, BM.Rotation())
                );
        }

        #region autoattack
        Composite AutoAttack()
        {
            return new Action(ret =>
            {
                Lua.DoString("StartAttack()");
                return RunStatus.Failure;
            });
        }
        #endregion

        #region AutoBot
        bool AutoBot
        {
            get
            {
                return usedBot.Contains("QUEST") || usedBot.Contains("GRIND") || usedBot.Contains("GATHER") || usedBot.Contains("ANGLER") || usedBot.Contains("ARCHEO");

            }
        }
        #endregion

        #region can buff
        public bool CanBuff
        {
            get
            {
                return !Me.Mounted && !Me.IsFlying && !Me.OnTaxi && !Me.IsDead && !Me.IsGhost && !Me.IsCasting;
            }
        }
        #endregion

        #region Hold
        Composite Hold()
        {
            return new Action(ret =>
            {
                return;
            });
        }
        #endregion

        #region use flasks, healthstone
        public uint crystal = 86569;
        public uint AgilityFlask = 76084;
        public uint AlchemyFlask = 75525;
        public uint healthstone = 5512;
        public uint CRYSTAL_OF_INSANITY_BUFF = 127230;
        #endregion

        
    }
}
